using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using System.Xml;
using System.IO;
using System.Xml.Serialization;


namespace Helper
{
    
    [Serializable]
    [XmlRoot()]
    public class Fonts : IDisposable
    {
        [XmlIgnore()]
        public Texture2D Texture;


        [XmlIgnore()]
        SpriteBatch fontRenderer;

        string fontFamily;
        public string FontFamily
        {
            get { return fontFamily; }
            set { fontFamily = value; }
        }

        int height;
        public int Height
        {
            get { return height; }
            set { height = value; }
        }

        int kerning = 0;
        public int Kerning
        {
            get { return kerning; }
            set { kerning = value; }
        }

        [Serializable()]
        public class XNAFontUV
        {
            [XmlAttribute()]
            public int U;

            [XmlAttribute()]
            public int V;

            [XmlAttribute()]
            public int Width;

            [XmlAttribute()]
            public char C;

            public XNAFontUV()
            {
                U = 0;
                V = 0;
                Width = 0;
                C = (char)0;
            }

            public XNAFontUV(int u, int v, char c, int Width)
            {
                this.U = u;
                this.V = v;
                this.C = c;
                this.Width = Width;
            }
        }

        [XmlIgnore()]
        public Dictionary<char, XNAFontUV> UVData = new Dictionary<char, XNAFontUV>();

        public List<XNAFontUV> UVList;

        /// <summary>
        /// Font to render
        /// </summary>
        internal class FontToRender
        {
            #region Variables
            /// <summary>
            /// X and y position
            /// </summary>
            public int x, y;
            /// <summary>
            /// Text
            /// </summary>
            public string text;
            /// <summary>
            /// Color
            /// </summary>
            public Color color;
            #endregion

            #region Constructor
            /// <summary>
            /// Create font to render
            /// </summary>
            /// <param name="setX">Set x</param>
            /// <param name="setY">Set y</param>
            /// <param name="setText">Set text</param>
            /// <param name="setColor">Set color</param>
            public FontToRender(int setX, int setY, string setText, Color setColor)
            {
                x = setX;
                y = setY;
                text = setText;
                color = setColor;
            } // FontToRender(setX, setY, setText)
            #endregion
        } // class FontToRender

        /// <summary>
        /// Remember font texts to render to render them all at once
        /// in our Render method (beween rest of the ui and the mouse cursor).
        /// </summary>
        static List<FontToRender> remTexts = new List<FontToRender>();

        /// <summary>
        /// Write the given text at the specified position.
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <param name="text">Text</param>
        /// <param name="color">Color</param>
        public static void WriteText(int x, int y, string text, Color color)
        {
            //return font.Write(x, y, text, color);
            remTexts.Add(new FontToRender(x, y, text, color));
        } // WriteText(x, y, text)

        /// <summary>
        /// Write
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <param name="text">Text</param>
        public static void WriteText(int x, int y, string text)
        {
            //return font.Write(x, y, text);
            remTexts.Add(new FontToRender(x, y, text, Color.White));
        } // WriteText(x, y, text)
        /// <summary>
        /// Write all
        /// </summary>
        /// <param name="texts">Texts</param>

        public void OutputText(string str, int x, int y, Color col)
        {
            int iCurrentX = x;
            int iCurrentY = y;

            fontRenderer.Begin(SpriteBlendMode.AlphaBlend);
            foreach (char c in str)
            {
                XNAFontUV uv = UVData[c];

                if (c != ' ')
                {
                    fontRenderer.Draw(Texture,
                        new Rectangle(iCurrentX, iCurrentY,
                            uv.Width, height),
                        new Rectangle(uv.V - 2,
                                      uv.U,
                                      uv.Width, height),
                        col);
                }

                iCurrentX += uv.Width - kerning;
            }
            fontRenderer.End();
        }

        public void WriteAll()
        {
            if (remTexts.Count == 0)
                return;

            // Start rendering
            fontRenderer.Begin(SpriteBlendMode.AlphaBlend);

            // Draw each character in the text
            //foreach (UIRenderer.FontToRender fontText in texts)
            for (int textNum = 0; textNum < remTexts.Count; textNum++)
            {
                FontToRender fontText = remTexts[textNum];

                int x = fontText.x;
                int y = fontText.y;
                Color color = fontText.color;
                string str = fontText.text;

                foreach (char c in str)
                {
                    XNAFontUV uv = UVData[c];

                    if (c != ' ')
                    {
                        fontRenderer.Draw(Texture,
                            new Rectangle(x, y,
                                uv.Width, height),
                            new Rectangle(uv.V - 2,
                                          uv.U,
                                          uv.Width, height),
                            color);
                    }

                    x += uv.Width - kerning;
                }
            }
            fontRenderer.End();
            remTexts.Clear();
        }

        public static Fonts LoadFont(GraphicsDevice device, string strXML)
        {
            XmlSerializer fontLoader = new XmlSerializer(typeof(Fonts));

            Stream reader = new FileStream("content/"+strXML, FileMode.Open);

            Fonts ret = (Fonts)fontLoader.Deserialize(reader);

            reader.Close();

            ret.UVData = new Dictionary<char, XNAFontUV>();
            foreach (XNAFontUV uv in ret.UVList)
            {
                ret.UVData.Add(uv.C, uv);
            }

            ret.UVList = null;

            ret.Texture = Texture2D.FromFile(device, "content/"+strXML + ".dds");
            ret.fontRenderer = new SpriteBatch(device);

            return ret;
        }

        public void SaveFont(string strXML)
        {

            Texture.Save(strXML + ".dds", ImageFileFormat.Dds);

            XmlSerializer fontWriter = new XmlSerializer(typeof(Fonts));

            Stream outputStream = File.Open(strXML, FileMode.Create);

            Dictionary<char, XNAFontUV>.Enumerator iter = UVData.GetEnumerator();

            UVList = new List<XNAFontUV>();

            while (iter.MoveNext())
            {

                UVList.Add(iter.Current.Value);
            }


            fontWriter.Serialize(outputStream, this);

            outputStream.Close();

            UVList = null;
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (Texture != null)
                Texture.Dispose();

            if (fontRenderer != null)
                fontRenderer.Dispose();

            Texture = null;
            fontRenderer = null;
        }

        #endregion
    }
}
